#pragma once
#pragma warning( disable : 4290 )

#include <Windows.h>
#include <string>
#include <vector>
#include <IllegalArgumentException.h>

using namespace std;

template <class TPixel>
class BitMap
{
private:
	BITMAPFILEHEADER _bmpFileHeader;
	BITMAPINFOHEADER _bmpInfoHeader;
	vector <TPixel> _imageData;
	vector<RGBQUAD> _palette ;
	int _padding;
public:

	BitMap(BITMAPFILEHEADER bmpHeader,	BITMAPINFOHEADER bmpInfo, vector<RGBQUAD> palette, vector<TPixel> imageData) throw(IllegalArgumentException){
			if(imageData.empty()){
				throw IllegalArgumentException("BitMap Class, image data is empty");
			}
			int sizeImage = bmpInfo.biSizeImage;

			if (sizeImage<0)
			{
				sizeImage=sizeImage*(-1);
			}

			if (imageData.empty())
			{
				throw IllegalArgumentException("BitMap Class, Image data empty");
			}

			if (sizeImage!=imageData.size()){
				throw IllegalArgumentException("BitMap Class, illegal image header or image size");
			}

			if(sizeof(bmpHeader) != sizeof(BITMAPFILEHEADER)){
				throw IllegalArgumentException("BitMap Class, illegal image header size");
			}
			_bmpInfoHeader = bmpInfo;
			_bmpFileHeader=bmpHeader;
			_palette = palette;
			_imageData=imageData;
			_padding = 3*bmpInfo.biWidth%4;
	};

	BitMap operator = (BitMap bitmap){
		BitMap bmp(bitmap.getBitmapFileHeader(),bitmap.getBitmapInfoHeader(), bitmap.getPalette(), bitmap.getImageData());
		return bmp;
	};

	~BitMap(void){};

	BITMAPFILEHEADER getBitmapFileHeader(){
		return _bmpFileHeader;
	};

	BITMAPINFOHEADER getBitmapInfoHeader(){
		return _bmpInfoHeader;
	};

	std::vector<RGBQUAD> getPalette(){
		return _palette;
	};

	std::vector <unsigned char> getImageData(){
		return _imageData;
	};


	unsigned char getPixel(int widthIndex,int heightIndex) throw(IllegalArgumentException){
		if (widthIndex>=_bmpInfoHeader.biWidth){
			throw IllegalArgumentException("BitMap Class, out of range");
		}

		if (heightIndex>=_bmpInfoHeader.biHeight){
			throw IllegalArgumentException("BitMap Class, out of range");
		}

		return _imageData[ (_bmpInfoHeader.biWidth+_padding)*heightIndex  + widthIndex];
	};


	BitMap getBimapArea(unsigned int x1, unsigned int y1, unsigned int x2, unsigned int y2) throw(IllegalArgumentException){
		vector<unsigned char> bitMapData;
		bitMapData.clear();
		int maxX, maxY;
		int minX, minY;

		if (x1<x2)
		{
			minX=x1;
			maxX=x2;
		}
		else{
			minX=x2;
			maxX=x1;
		}

		if (y1<y2)
		{
			minY=y1;
			maxY=y2;
		} 
		else
		{
			minY=y2;
			maxY=y1;
		}

		if(maxX>=_bmpInfoHeader.biWidth){
			throw IllegalArgumentException("BitMap Class, out of range");
		}

		if (maxY>=_bmpInfoHeader.biHeight){
			throw IllegalArgumentException("BitMap Class, out of range");
		}

		int padding = 3*(maxX+1)%4;

		for(int i=minY;i<=maxY;i++){
			for(int j=minX;j<=maxX;j++){
				bitMapData.push_back(getPixel(j,i));
			}

			for(int p=0;p<padding;p++){
				bitMapData.push_back(0);
			}
		}

		BITMAPINFOHEADER infoHeader;
		infoHeader = _bmpInfoHeader;
		infoHeader.biWidth = maxX-minX+1;
		infoHeader.biHeight = maxY-minY+1;
		infoHeader.biSizeImage = bitMapData.size();
		BITMAPFILEHEADER fileHeader;
		fileHeader = _bmpFileHeader;
		fileHeader.bfSize = infoHeader.biSizeImage+_bmpFileHeader.bfOffBits;

		BitMap bmp(fileHeader,infoHeader,_palette,bitMapData);
		return bmp;
	};
};

